/* Includes ------------------------------------------------------------------*/
#include "SystemTick.h"
#include "Led.h"
#include "Encoder.h"
#include "UART.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define DEVICE_ADDR 0x80
#define MAX_TX_LEN  32
#define MAX_RX_LEN  32
#define STX         03
#define ETX         04

#define MIN_FRAME_LENGTH    4

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8          s_pTxBuff[MAX_TX_LEN];
__IO u8     s_TxIndex = 0;
u8          s_TxLength = 0;
__IO bool   s_TxSendingFlag = FALSE;

u8          s_pRxBuff[MAX_RX_LEN];
__IO u8     s_RxLength = 0;
__IO bool   s_RxFlag = FALSE;
bool        s_RxWaitNewPackedFlag = TRUE;

#define TIMEOUT_FRAME    5

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8   s_TimeoutCnt = 0;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
void UART_ResetTimeout(void);
u16 UART_GenerateChecksum(u8* pDataIn, u8 iLen);

// UART1 TX Interrupt routine
INTERRUPT_HANDLER(UART1_TX_IRQHandler, 17)
{
    if (s_TxIndex < s_TxLength)
    {
        UART1_SendData8(s_pTxBuff[s_TxIndex++]);
    }
    else
    {
        s_TxSendingFlag = FALSE;
        UART1_ITConfig(UART1_IT_TXE, DISABLE);
    }
}

// UART1 RX Interrupt routine
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
    u8 data = UART1_ReceiveData8();
    if (TRUE == s_RxWaitNewPackedFlag && DEVICE_ADDR == data)
    {
        s_RxLength = 0;
        s_RxWaitNewPackedFlag = FALSE;
    }
    
    if (MAX_RX_LEN <= s_RxLength)
    {
        s_RxLength = 0;
    }

    s_pRxBuff[s_RxLength++] = data;

    UART_ResetTimeout();
}


void UART_ResetTimeout(void)
{
    s_TimeoutCnt = 0;
}


void UART_TimerInterrupt(void)
{
    if ( TRUE == s_RxWaitNewPackedFlag ) return;

    if (TIMEOUT_FRAME <= ++s_TimeoutCnt)
    {
        s_RxFlag = TRUE;
        s_RxWaitNewPackedFlag = TRUE;
    }
}


void Memcpy(u8* pDest, u8* pSrc, u8 iLen)
{
    while (iLen--)
    {
        *pDest = *pSrc;
        ++pDest;
        ++pSrc;
    }
}


bool UART_Send(u8* pData, u8 iLen)
{
    if (TRUE == s_TxSendingFlag) return (FALSE);
    Memcpy(s_pTxBuff, pData, iLen);
    s_TxIndex = 0;
    s_TxLength = iLen;
    s_TxSendingFlag = TRUE;
    UART1_ITConfig(UART1_IT_TXE, ENABLE);

    return (TRUE);
}


void UART_Init(void)
{
    /* De-initializes the UART1 and UART3 peripheral */
    UART1_DeInit();
    /* UART1configuration -------------------------------------------------*/
    /* UART1configured as follow:
    - BaudRate = 9600 baud  
    - Word Length = 8 Bits
    - One Stop Bit
    - No parity
    - Receive and transmit enabled
    - UART1 Clock disabled
    */
    UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO,
        UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);

    /* Enable UART1 Transmit interrupt*/
    UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
    UART1_ITConfig(UART1_IT_TXE, DISABLE);

    SysTick_Registration(&UART_TimerInterrupt);
}


void UART_Reply(u8 iCmd, u8* pData, u8 iLen)
{
    while (TRUE == s_TxSendingFlag);
    s_pTxBuff[0] = DEVICE_ADDR;
    s_pTxBuff[1] = iCmd;
    Memcpy(&s_pTxBuff[2], pData, iLen);
    *((u16*)(&s_pTxBuff[iLen+2])) = UART_GenerateChecksum(s_pTxBuff, iLen+2);
    s_TxIndex = 0;
    s_TxLength = iLen+4;
    s_TxSendingFlag = TRUE;
    UART1_ITConfig(UART1_IT_TXE, ENABLE);
}


u8 HexToAscii(u8 iHex)
{
    u8 temp = iHex & 0x0F;
    if (9 < temp) temp += 7;
    return (temp + '0');
}


u8 AsciiToHex(u8 iAscii)
{
    u8 temp = iAscii & 0x7F;
    if ('9' < temp) temp += 9;
    return (temp & 0x0F);
}


void HexToStrByte(u8* pStr, u8 iHex)
{
    pStr[0] = HexToAscii(iHex >> 4);
    pStr[1] = HexToAscii(iHex & 0x0F);
}

void HexToStrWord(u8* pStr, u16 iHex)
{
    pStr[0] = HexToAscii(iHex >> 12);
    pStr[1] = HexToAscii(iHex >> 8);
    pStr[2] = HexToAscii(iHex >> 4);
    pStr[3] = HexToAscii(iHex & 0x0F);
}

void UART_Processor(u8* pDataIn, u8 iLen)
{
    u8 pBuff[MAX_TX_LEN - 2];

    switch (pDataIn[1])
    {
    case GET_STATUS:
        {
            pBuff[0] = GetSWStatus();
            *((u32*)(&pBuff[1])) = Encoder_GetStatus();
            UART_Reply(GET_STATUS,pBuff,5);
        } break;
   
    case SET_SAMPLE_TIMER:
        {
            Encoder_SetSampleTimer( *((u16*)(&pDataIn[2])) );
            *((u16*)(&pBuff[0])) = Encoder_GetSampleTimer();
            UART_Reply(SET_SAMPLE_TIMER, pBuff, 2);
        } break;
   
    // case 0x03:
        // {
            // pBuff[0]  = 0x01;
            // pBuff[1]  = 0x03;
            // pBuff[2]  = 0x0C;
            // pBuff[3]  = 0x00;
            // pBuff[4]  = 0x03;
            // pBuff[5]  = 0x00;
            // pBuff[6]  = 0x00;
            // pBuff[7]  = 0x00;
            // pBuff[8]  = 0x63;
            // pBuff[9]  = 0x00;
            // pBuff[10] = 0x00;
            // pBuff[11] = 0x00;
            // pBuff[12] = 0x1E;
            // pBuff[13] = 0x01;
            // pBuff[14] = 0x1C;
            // pBuff[15] = 0xAF;
            // pBuff[16] = 0x6D;
            // UART_Send(pBuff,17);
        // } break;
            
    default:
        {
            UART_Reply('N',"",0);
        } break;
    }
}


u16 UART_GenerateChecksum(u8* pDataIn, u8 iLen)
{
    u16 temp;
    u16 crc = 0xFFFF;
    u8 i, j;

    for (i=0; i<iLen; i++)
    {
        crc = ((crc^pDataIn[i]) | 0xFF00) & (crc | 0x00FF);
        for (j=0; j<8; j++)
        {
            temp = crc & 0x0001;
            crc >>= 1;
            if (temp)
            {
                crc ^= 0xA001;
            }
        }
    }

    return (crc);
}


bool UART_FrameIsCorrect(u8* pDataIn, u8 iLen)
{
    u16 crc;
    // kiem tra xem frame co dung voi format quy dinh ko
    if ( (DEVICE_ADDR != pDataIn[0]) || (MIN_FRAME_LENGTH > iLen) ) return (FALSE);

    // kiem tra checksum xem co dung khong
    crc = UART_GenerateChecksum(pDataIn, iLen - 2);
    if ( pDataIn[iLen - 1] == (u8)(crc>>8) && pDataIn[iLen - 2] == (u8)crc ) return (TRUE);
    else return (FALSE);
}


void UART_RunOne(void)
{
    if (FALSE == s_RxFlag) return;
    s_RxFlag = FALSE;

    if ( FALSE == UART_FrameIsCorrect(s_pRxBuff, s_RxLength) ) return;

    UART_Processor(s_pRxBuff, s_RxLength);
}
